package com.youdianstar.app.common.network

import android.util.Log
import com.google.gson.JsonParser
import com.youdianstar.app.common.DataCode
import com.youdianstar.app.common.HttpCode
import com.youdianstar.app.common.entity.BusEntity
import com.youdianstar.app.common.network.model.BaseResponse
import com.youdianstar.app.common.network.model.DataState
import com.youdianstar.app.common.event.NetStateLiveData
import com.safframework.eventbus.EventBus
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.*
import com.youdianstar.app.common.util.ApiLogger
import com.youdianstar.app.common.util.LogUtil
import com.youdianstar.app.common.util.ApiRequestContext
import retrofit2.HttpException
import java.net.UnknownHostException
import java.net.ConnectException
import java.net.SocketTimeoutException
import java.io.InterruptedIOException


/**
 * File: BaseRepository
 * Author: 82149 Create: 2021/9/22 19:19
 * Changes (from 2021/9/22)
 * --------------------------------------------------
 * description: 数据逻辑中间层:网络请求+基础逻辑处理
 * ---------------------------------------------------
 *
 */
open class BaseRepository {

    companion object {
        private const val TAG = "BaseRepository"
        // 防抖机制：记录最后一次发送TOKEN_OUT事件的时间戳
        @Volatile
        private var lastTokenOutEventTime: Long = 0
        // 防抖时间间隔：2秒内不重复发送TOKEN_OUT事件
        private const val TOKEN_OUT_DEBOUNCE_INTERVAL = 2000L
        
        /**
         * 处理TOKEN_OUT事件，带防抖机制
         * 确保在短时间内（2秒）只发送一次TOKEN_OUT事件，避免多个接口同时返回460时重复跳转
         */
        @JvmStatic
        internal fun handleTokenOutEvent(logMessage: String) {
            val currentTime = System.currentTimeMillis()
            val timeSinceLastEvent = currentTime - lastTokenOutEventTime
            
            if (timeSinceLastEvent >= TOKEN_OUT_DEBOUNCE_INTERVAL) {
                // 距离上次发送事件已超过防抖间隔，可以发送新事件
                lastTokenOutEventTime = currentTime
                LogUtil.w("---Token expired detected: $logMessage")
                EventBus.post(BusEntity(DataCode.TOKEN_OUT), 0L)
            } else {
                // 距离上次发送事件时间太短，忽略本次事件，避免重复跳转
                LogUtil.d("---Token expired event ignored (debounced): $logMessage, timeSinceLastEvent=${timeSinceLastEvent}ms")
            }
        }
    }

    /**
     * 方式二：结合Flow请求数据。
     * 根据Flow的不同请求状态，如onStart、onEmpty、onCompletion等设置baseResp.dataState状态值，
     * 最后通过stateLiveData分发给UI层。
     *
     * @param block api的请求方法
     * @param netStateLiveData 每个请求传入相应的LiveData，主要负责网络状态的监听
     */
    suspend fun <T : Any> executeReqWithFlow(
        block: suspend () -> BaseResponse<T>,
        netStateLiveData: NetStateLiveData<T>
    ) {
        var baseResp = BaseResponse<T>()
        flow {
            val respResult = block.invoke()
            baseResp = respResult
            Log.d(TAG, "executeReqWithFlow: $baseResp")
            baseResp.dataState = DataState.STATE_SUCCESS
            netStateLiveData.postValue(baseResp)
            emit(respResult)
        }
            .flowOn(Dispatchers.IO)
            .onStart {
                Log.d(TAG, "executeReqWithFlow:onStart")
                baseResp.dataState = DataState.STATE_LOADING
                netStateLiveData.postValue(baseResp)
            }
            .onEmpty {
                Log.d(TAG, "executeReqWithFlow:onEmpty")
                baseResp.dataState = DataState.STATE_EMPTY
                netStateLiveData.postValue(baseResp)
            }
            .catch { exception ->
                run {
                    Log.d(TAG, "executeReqWithFlow:code  ${baseResp.code}")
                    exception.printStackTrace()
                    baseResp.dataState = DataState.STATE_ERROR
                    baseResp.error = exception
                    netStateLiveData.postValue(baseResp)
                }
            }
            .collect {
                Log.d(TAG, "executeReqWithFlow: collect")
                netStateLiveData.postValue(baseResp)
            }


    }

    /**
     * 方式一
     * repo 请求数据的公共方法，
     * 在不同状态下先设置 baseResp.dataState的值，最后将dataState 的状态通知给UI
     * @param block api的请求方法
     * @param netStateLiveData 每个请求传入相应的LiveData，主要负责网络状态的监听
     */
    suspend fun <T : Any> executeResp(
        block: suspend () -> BaseResponse<T>,
        netStateLiveData: NetStateLiveData<T>
    ) {
        var baseResp = BaseResponse<T>()
        try {
            baseResp.dataState = DataState.STATE_LOADING
            Log.d(TAG, "开始请求API...")
            //开始请求数据
            val invoke = block.invoke()
            //将结果复制给baseResp
            baseResp = invoke
            ApiLogger.logResponse("API请求", baseResp.code, baseResp.message, baseResp.data)
            if (baseResp.code == 0 || baseResp.code == 200) {
                //请求成功，判断数据是否为空
                if (baseResp.data == null || baseResp.data is List<*> && (baseResp.data as List<*>).size == 0) {
                    //数据为空,结构变化时需要修改判空条件
                    baseResp.dataState = DataState.STATE_EMPTY
                } else {
                    //请求成功并且数据为空的情况下，为STATE_SUCCESS
                    baseResp.dataState = DataState.STATE_SUCCESS
                }
            } else {
                baseResp.dataState = DataState.STATE_FAILED
                if (baseResp.code == HttpCode.CODE_TOKEN_OUT || baseResp.code == 460){
                    handleTokenOutEvent("code=${baseResp.code}, message=${baseResp.message}")
                }
            }
        } catch (e: Exception) {
            // 尝试从请求上下文获取请求信息
            val requestContext = ApiRequestContext.getContext()
            val apiName = requestContext?.apiName ?: "API请求"
            
            // 从 HttpException 中尝试获取请求信息
            var requestUrl: String? = null
            var requestMethod: String? = null
            if (e is HttpException) {
                val request = e.response()?.raw()?.request
                requestUrl = request?.url?.toString()
                requestMethod = request?.method
            }
            
            // 使用请求上下文信息或从异常中提取的信息记录异常
            ApiLogger.logException(
                apiName = apiName,
                exception = e,
                url = requestContext?.url ?: requestUrl,
                method = requestContext?.method ?: requestMethod,
                params = requestContext?.params,
                requestBody = requestContext?.requestBody
            )
            
            // 清除请求上下文
            ApiRequestContext.clearContext()
            
            // 处理HttpException，尝试解析响应体中的错误信息
            if (e is HttpException) {
                try {
                    val response = e.response()
                    val errorBody = response?.errorBody()?.string()
                    
                    if (!errorBody.isNullOrEmpty()) {
                        // 尝试解析JSON响应体
                        val jsonElement = JsonParser.parseString(errorBody)
                        if (jsonElement.isJsonObject) {
                            val jsonObject = jsonElement.asJsonObject
                            
                            // 提取code字段
                            val errorCode = if (jsonObject.has("code")) {
                                jsonObject.get("code").asInt
                            } else {
                                response.code()
                            }
                            
                            // 提取msg或message字段作为错误信息
                            val errorMsg = when {
                                jsonObject.has("msg") -> jsonObject.get("msg").asString
                                jsonObject.has("message") -> jsonObject.get("message").asString
                                else -> e.message() ?: "HTTP ${response.code()}"
                            }
                            
                            // 设置错误码和错误信息
                            baseResp.code = errorCode
                            baseResp.message = errorMsg
                            
                            // 如果是460错误（会话过期），发送TOKEN_OUT事件
                            // MainActivity会处理该事件，清空token和登录信息并跳转到登录页面
                            if (errorCode == 460 || errorCode == HttpCode.CODE_TOKEN_OUT) {
                                handleTokenOutEvent("code=$errorCode, message=$errorMsg")
                            }
                            
                            // 设置为FAILED状态，这样会触发onNetError回调并传递错误信息
                            baseResp.dataState = DataState.STATE_FAILED
                            LogUtil.d("---Parsed HTTP error: code=$errorCode, message=$errorMsg")
                        } else {
                            // JSON解析失败，使用HTTP状态码和默认错误信息
                            baseResp.code = response.code()
                            baseResp.message = e.message() ?: "HTTP ${response.code()}"
                            baseResp.dataState = DataState.STATE_ERROR
                            baseResp.error = e
                        }
                    } else {
                        // 响应体为空，使用HTTP状态码
                        baseResp.code = response?.code() ?: -1
                        baseResp.message = e.message() ?: "HTTP ${response?.code() ?: -1}"
                        baseResp.dataState = DataState.STATE_ERROR
                        baseResp.error = e
                    }
                } catch (parseException: Exception) {
                    // JSON解析失败，使用HTTP状态码和默认错误信息
                    LogUtil.e("---Failed to parse error response: ${parseException.message}")
                    baseResp.code = e.response()?.code() ?: -1
                    baseResp.message = e.message() ?: "HTTP ${e.response()?.code() ?: -1}"
                    baseResp.dataState = DataState.STATE_ERROR
                    baseResp.error = e
                }
            } else {
                // 处理其他网络异常，如 UnknownHostException, ConnectException 等
                baseResp.error = e
                
                // 根据异常类型设置友好的错误消息
                val errorMessage = when (e) {
                    is UnknownHostException -> {
                        // DNS解析失败，无法连接到服务器
                        val host = e.message?.substringAfter("Unable to resolve host \"")?.substringBefore("\"") ?: "server"
                        "Unable to connect to $host. Please check your network connection."
                    }
                    is ConnectException -> {
                        // 连接失败
                        "Connection failed. Please check your network connection."
                    }
                    is SocketTimeoutException, is InterruptedIOException -> {
                        // 连接超时
                        "Connection timeout. Please try again later."
                    }
                    else -> {
                        // 其他异常，使用异常消息，如果没有则使用默认消息
                        e.message ?: "Network request failed. Please try again."
                    }
                }
                
                // 设置错误码和错误消息
                baseResp.code = -1
                baseResp.message = errorMessage
                
                // 设置为FAILED状态，这样会触发onNetError回调并传递错误信息
                baseResp.dataState = DataState.STATE_FAILED
                
                // 打印详细的错误信息到日志
                LogUtil.e("---Network error: ${e.javaClass.simpleName}, message=$errorMessage")
                LogUtil.e("---Exception details: ${e.message}")
            }
        } finally {
            // 确保清除请求上下文
            ApiRequestContext.clearContext()
            netStateLiveData.postValue(baseResp)
        }
    }

}